package ttelectronic.mobileholder.service;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

import ttelectronic.mobileholder.common.MHCommon;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

public class MHBluetoothConnectingService {
	// Unique UUID for this application
	private static final UUID appsUUID = UUID
			.fromString("00001101-0000-1000-8000-00805F9B34FB");

	// Member fields
	private Context mContext;
	private final BluetoothAdapter mBluetoothAdapter;
	private final Handler mHandler;

	// Connect device
	private AcceptThread mAcceptThread;
	private ConnectThread mConnectThread;
	private ConnectedThread mConnectedThread;
	private int mState;

	// socket
	private BluetoothSocket mSocket = null;

	// private BroadcastReceiver smsReceiver = new BroadcastReceiver() {
	//
	// @Override
	// public void onReceive(Context context, Intent intent) {
	// Bundle bundle = intent.getExtras();
	// if (null != bundle) {
	// String info = "m";
	// OutputStream mOutPut = null;
	// try {
	// mOutPut = mSocket.getOutputStream();
	// } catch (IOException e) {
	// e.printStackTrace();
	// }
	// PrintWriter pWriter = new PrintWriter(new OutputStreamWriter(
	// mOutPut));
	// pWriter.write(info);
	// pWriter.write("s");
	// pWriter.flush();
	// }
	// }
	// };

	private BroadcastReceiver callstateReceiver = new BroadcastReceiver() {
		public int mLastState = TelephonyManager.CALL_STATE_IDLE;

		@Override
		public void onReceive(Context context, Intent intent) {
			MHPhoneStateListener phoneListener = new MHPhoneStateListener(
					mContext, mSocket, mLastState);
			TelephonyManager telephony = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);
			telephony.listen(phoneListener,
					PhoneStateListener.LISTEN_CALL_STATE);
		}
	};

	public MHBluetoothConnectingService(Context context, Handler handler) {
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		mState = MHCommon.STATE_NONE;
		mHandler = handler;
		mContext = context;

		// register broadcast
		// mContext.getApplicationContext().registerReceiver(batteryLevelReceiver,
		// new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
		// mContext.getApplicationContext().registerReceiver(smsReceiver,
		// new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));

		mContext.getApplicationContext().registerReceiver(callstateReceiver,
				new IntentFilter("android.intent.action.PHONE_STATE"));
	}

	public synchronized void connect(BluetoothDevice device) {
		if (mState == MHCommon.STATE_CONNECTING)
			if (mConnectThread != null) {
				mConnectThread.cancel();
				mConnectThread = null;
			}
		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
		// Start the thread to connect with the given device
		mConnectThread = new ConnectThread(device);
		mConnectThread.start();

		setState(MHCommon.STATE_CONNECTING);
	}

	/**
	 * Start the ConnectedThread to begin managing a Bluetooth connection
	 * 
	 * @param socket
	 *            The BluetoothSocket on which the connection was made
	 * @param device
	 *            The BluetoothDevice that has been connected
	 */
	public synchronized void connected(BluetoothSocket socket,
			BluetoothDevice device) {
		// Cancel the thread that completed the connection
		if (mConnectThread != null) {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		// Cancel the accept thread because we only want to connect to one
		// device
		if (mAcceptThread != null) {
			mAcceptThread.cancel();
			mAcceptThread = null;
		}

		mSocket = socket;
		// Start the thread to manage the connection and perform transmissions
		mConnectedThread = new ConnectedThread(socket);
		mConnectedThread.start();

		Message msg = mHandler.obtainMessage(MHCommon.MESSAGE_DEVICE_NAME);
		Bundle bundle = new Bundle();
		bundle.putString(MHCommon.DEVICE_NAME, device.getName());
		msg.setData(bundle);
		mHandler.sendMessage(msg);

		MHPinInformationService pingInformationSerice = new MHPinInformationService(
				mContext, socket, mHandler);
		pingInformationSerice.start();

		Log.d(MHCommon.TAG + "Thread", "Start Miss Call service");
		MHMissCallService missCallService = new MHMissCallService(mContext,
				mHandler, socket);
		missCallService.start();

		Log.d(MHCommon.TAG + "Thread", "Start Alarm service");
		MHAlarmService alarmService = new MHAlarmService(socket, mContext);
		alarmService.start();

		Log.d(MHCommon.TAG + "Thread", "Start SMS service");
		MHSMSService smsService = new MHSMSService(mContext, mSocket, mHandler);
		smsService.start();

		Log.d(MHCommon.TAG + "Thread", "started all service");
		setState(MHCommon.STATE_CONNECTED);

	}

	private synchronized void setState(int state) {
		mState = state;
		mHandler.obtainMessage(MHCommon.MESSAGE_STATE_CHANGE, state, -1)
				.sendToTarget();
	}

	/**
	 * Return the current connection state.
	 */
	public synchronized int getState() {
		return mState;
	}

	/**
	 * Indicate that the connection attempt failed and notify the UI Activity.
	 */
	private void connectionFailed() {
		setState(MHCommon.STATE_LISTEN);
	}

	// Indicate that the connection was lost and notify the UI Activity.
	private void connectionLost() {
		setState(MHCommon.STATE_LISTEN);
	}

	// Start the chat service. Specifically start AcceptThread to begin a
	// session in listening (server) mode. Called by the Activity onResume()
	public synchronized void start() {
		// Cancel any thread attempting to make a connection
		if (mConnectThread != null) {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		// Start the thread to listen on a BluetoothServerSocket
		if (mAcceptThread == null) {
			mAcceptThread = new AcceptThread();
			mAcceptThread.start();
		}
		// setState(MHCommon.STATE_LISTEN);
	}

	/**
	 * Stop all threads
	 */
	public synchronized void stop() {
		if (mConnectThread != null) {
			mConnectThread.cancel();
			mConnectThread = null;
		}
		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
		if (mAcceptThread != null) {
			mAcceptThread.cancel();
			mAcceptThread = null;
		}
		setState(MHCommon.STATE_NONE);
	}

	public void write(byte[] out) {
		// Create temporary object
		// ConnectedThread r;
		// Synchronize a copy of the ConnectedThread
		synchronized (this) {
			if (mState != MHCommon.STATE_CONNECTED)
				return;
			// r = mConnectedThread;
		}
		// Perform the write unsynchronized
		// r.write(out);
	}

	public void write(int out) {
		// Synchronize a copy of the ConnectedThread
		synchronized (this) {
			if (mState != MHCommon.STATE_CONNECTED)
				return;
		}
	}

	private class AcceptThread extends Thread {
		// The local server socket
		private final BluetoothServerSocket mmServerSocket;

		public AcceptThread() {
			BluetoothServerSocket tmp = null;
			// Create a new listening server socket
			try {
				tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(
						MHCommon.NAME_SOCKET, appsUUID);
			} catch (IOException e) {
			}
			mmServerSocket = tmp;
		}

		public void run() {
			setName("AcceptThread");
			BluetoothSocket socket = null;

			// Listen to the server socket if we're not connected
			while (mState != MHCommon.STATE_CONNECTED) {
				try {
					// This is a blocking call and will only return on a
					// successful connection or an exception
					socket = mmServerSocket.accept();
				} catch (IOException e) {
					// Log.e(TAG, "accept() failed", e);
					break;
				}

				// If a connection was accepted
				if (socket != null) {
					synchronized (MHBluetoothConnectingService.this) {
						switch (mState) {
						case MHCommon.STATE_LISTEN:
							break;
						case MHCommon.STATE_CONNECTING:
							// Situation normal. Start the connected thread.
							connected(socket, socket.getRemoteDevice());
							break;
						case MHCommon.STATE_NONE:
							break;
						case MHCommon.STATE_CONNECTED:
							try {
								socket.close();
							} catch (IOException e) {
							}
							break;
						}
					}
				}
			}
		}

		public void cancel() {
			try {
				mmServerSocket.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * This thread runs while attempting to make an outgoing connection with a
	 * device. It runs straight through; the connection either succeeds or
	 * fails.
	 */
	private class ConnectThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final BluetoothDevice mmDevice;

		public ConnectThread(BluetoothDevice device) {
			mmDevice = device;
			BluetoothSocket tmp = null;
			try {
				tmp = device.createRfcommSocketToServiceRecord(appsUUID);
			} catch (IOException e) {
				Log.d(MHCommon.TAG_E,
						"Unable create RFcommSocket at ConnectThread");
			}
			mmSocket = tmp;
		}

		public void run() {
			setName("ConnectThread");
			// Always cancel discovery because it will slow down a connection
			mBluetoothAdapter.cancelDiscovery();
			// Make a connection to the BluetoothSocket
			try {
				// This is a blocking call and will only return on a
				// successful connection or an exception
				mmSocket.connect();
			} catch (IOException e) {
				Log.d(MHCommon.TAG + " error: ", e.toString());
				connectionFailed();
				// Close the socket
				try {
					mmSocket.close();
				} catch (IOException e2) {
					Log.d(MHCommon.TAG_E,
							"Unable close socket in ConnectThread");
				}
				MHBluetoothConnectingService.this.start();
				return;
			}

			// Reset the ConnectThread because we're done
			synchronized (MHBluetoothConnectingService.this) {
				mConnectThread = null;
			}
			// Start the connected thread
			connected(mmSocket, mmDevice);
		}

		public void cancel() {
			try {
				mmSocket.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * This thread runs during a connection with a remote device. It handles all
	 * incoming and outgoing transmissions.
	 */
	private class ConnectedThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final InputStream mmInStream;

		// private final OutputStream mmOutStream;

		public ConnectedThread(BluetoothSocket socket) {
			mmSocket = socket;
			InputStream tmpIn = null;
			// OutputStream tmpOut = null;
			try {
				tmpIn = socket.getInputStream();
				// tmpOut = socket.getOutputStream();
			} catch (IOException e) {
			}
			mmInStream = tmpIn;
			// mmOutStream = tmpOut;
		}

		public void run() {
			byte[] buffer = new byte[1024];
			int bytes;
			while (true) {
				try {
					bytes = mmInStream.read(buffer);
					mHandler.obtainMessage(MHCommon.MESSAGE_READ, bytes, -1,
							buffer).sendToTarget();
				} catch (IOException e) {
					connectionLost();
					break;
				}
			}
		}

		// public void write(byte[] buffer) {
		// try {
		// mmOutStream.write(buffer);
		// mHandler.obtainMessage(MHCommon.MESSAGE_WRITE, -1, -1, buffer)
		// .sendToTarget();
		// } catch (IOException e) {
		// Log.d(MHCommon.TAG_E, e.toString());
		// }
		// }

		public void cancel() {
			try {
				mmSocket.close();
			} catch (IOException e) {
				Log.d(MHCommon.TAG_E, e.toString());
			}
		}
	}
}
